/*基环树DP
    基环树:由一个环和若干棵树组成。
           基环树是在一棵树上添加一条边，使得图中恰好形成一个环
    内向树的所有边都是指向根节点方向的
    外向树的所有边都从根节点指向其他节点

* 1.对于一棵基环树，如何快速求出任意两个点之间距离的最大值
    可以将所有点对分成两类，
    一类是两个点属于同一棵子树，则此时这两个点的路径只会用到子树内的边，不会用到环上的边，
    这样就是单纯在一棵树内求任意两个点之间距离的最大值也就是求树的直径，
    可以用树形dp来求，枚举子树上所有点作为最高点，求出向下走的最长路和次长路，就是经过当前点的直径，枚举所有点取一个最大值就是整棵子树的直径。
    
    另一类就是两个点不属于同一棵子树，此时这两个点之间的路径必然会经过环，
    我们可以将路径分成三部分，一部分是环上的路径，另外两部分是环上任意两个点往下走的路径，
    由于要求最大距离，因此这三部分都要尽可能的大，而环上每个点往下走的最长距离一定是固定的，
    因此我们可以预处理一下环上每个点往下走的最长距离 dist[i]，
    然后枚举环上任意两个点 a,b，此时这条路径应该是 dist[a]+dist[b]+S(a,b)
    其中S(a,b)表示a, b之间的最长距离。

* 2.S(a, b) == S(b, a)
    枚举一种方向，设a在b的顺时针方向上
    枚举a，即可枚举到环上所有的情况
    此时对于任意的a，需要在环上找到一个b，使得dist[a]+dist[b]+S(a,b)最大
    由于S(a,b)是一个区间和，预处理前缀和，设S[x]为顺时针方向前缀和，此时路径长度变为dist[a]+dist[b]+S[a]-S[b]
    此时a是固定的，因此dist[a]+S[a]是固定的，只需要求dist[b]-S[b]的最大值
    断环成链，z在将链复制接在其后，每次枚举链上长度为原环长度的区间，都是环上的一种情况
    在任意一种情况上取dist[b]-S[b]的最大值->滑动窗口求最值问题

* 3.dfs()找环
    用栈记录递归路径，找到路径中某点，则找到环

*/  

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define DEBUG
using ll=long long;
inline int read()
{
	int x=0;char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x;
}
inline void write(ll x)
{
	if (x>=10) write(x/10);
	putchar(x%10+48);
}//快读快输

const int N=1e6+10, M=N<<1;

int n;
int h[N], e[M], w[M], ne[M], idx;
int fa[N], faw[M]; //父节点 与父节点相连边的权值
bool st[N], in_stack[N];
int circle[N], ed[N], cnt; //所有环 每一段环的终点 个数
ll s[N]; //s[i]:i到所在环的第一个点的前缀和
ll dist[M], sum[M]; //拆环成链的新链表 前缀和
int q[N]; //单调队列
ll ans=0; //基环树的直径

inline void AddEdge(int a, int b, int c)
{
    e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}

void dfsCircle(int u, int from) //找出所有环 当前节点 从哪条边来的
{
    st[u]=in_stack[u]=true;
    for(int i=h[u]; ~i; i=ne[i])
    {
        if(i==(from^1)) continue;
        int v=e[i];
        fa[v]=u, faw[v]=w[i];
        if(!st[v]) dfsCircle(v, i);
        else if(in_stack[v]) //找到环
        {
            cnt++;
            ed[cnt]=ed[cnt-1]; //初始化当前环的终点索引
            //保证每个环的节点在circle数组中是连续存储的，并且不会覆盖上一个环的节点记录
            ll sum=w[i];
            for(int k=u; k!=v; k=fa[k])
            {
                s[k]=sum;
                sum+=faw[k];
                circle[++ed[cnt]]=k;
            }
            s[v]=sum, circle[++ed[cnt]]=v;
        }
    }
    in_stack[u]=false; //弹出
}

ll dfsDist(int u) //从u向下走的最大路径
{
    st[u]=true;
    ll mx=0, mx2=0; //最大 次大
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(st[v]) continue;
        ll dist = dfsDist(v)+w[i];
        if(dist>=mx) mx2=mx, mx=dist;
        else if(dist>mx2) mx2=dist;
    }
    ans=max(ans, mx+mx2);
    return mx;
}

void solve()
{
    memset(h, -1, sizeof h);

    n=read();
    
    for(int i=1; i<=n; i++)
    {
        int a=read(), b=read();
        AddEdge(i, a, b); AddEdge(a, i, b);
    }
    //找出基环树的环
    for(int i=1; i<=n; i++)
        if(!st[i])
            dfsCircle(i, -1);

    memset(st, 0, sizeof st);
    for(int i=1; i<=ed[cnt]; i++) st[circle[i]]=true; //标记环上的点

    ll res=0;
    for(int i=1; i<=cnt; i++) //遍历所有环
    {
        ans=0; //当前基环树直径
        int sz=0; //环大小
        for(int u=ed[i-1]+1; u<=ed[i]; u++) //找出环中所有点
        {
            int k=circle[u]; //u环上节点在circle中的下标 k当前环上的节点编号
            dist[sz]=dfsDist(k);
            sum[sz]=s[k];
            sz++;
        }

        for(int u=0; u<sz; u++) //拆环成链
            dist[sz+u]=dist[u], sum[sz+u]=sum[u]+sum[sz-1];
        
        //单调队列
        int hh=0, tt=-1;
        for(int u=0; u<sz<<1; u++)
        {
            if(hh<=tt && u-q[hh]+1>sz) hh++; //与队头元素距离超过环的大小 出队
            if(hh<=tt) ans=max(ans, dist[u]+sum[u]+dist[q[hh]]-sum[q[hh]]); //情况2
            while(hh<=tt && dist[q[tt]]-sum[q[tt]]<=dist[u]-sum[u]) tt--; //维护单调性
            q[++tt]=u;
        }
        res+=ans;
    }
    printf("%lld\n", res);
}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
        freopen("./out.txt","w",stdout);
    #endif

    
    int T=1; //T=read();
    while(T--)
    {
        solve();
    }
    return 0;
}